package com.corticon.dialogs.util.hibernate;

import com.corticon.dialogs.model.Auditable;
import com.corticon.dialogs.model.User;
import java.io.Serializable;

import java.util.Date;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.userdetails.UserDetails;

/**
 * TODO: Why |= be used?
 * @author Yanglifan
 */
public class AuditInterceptor extends EmptyInterceptor {

    private String updatedOnName = "modifiedOn";
    private String updatedByName = "modifiedBy";

    @Override
    public boolean onSave(Object entity, Serializable id, Object[] currentState,
            String[] propertyNames, Type[] types) {
        boolean updated = false;
        if (entity instanceof Auditable) {
            Auditable a = (Auditable) entity;
            String username = getCurrentUser();
            if (username.equals("") && entity instanceof User) {// When a user sign in, he/she's modifed by himself/herself
                User u = (User) entity;
                username = u.getUsername();
            }
            Date stamp = new Date();
            for (int i = 0; i < propertyNames.length; i++) {
                String propertyName = propertyNames[i];

                updated |= checkModifiedOn(currentState, a, stamp, i, propertyName);
//                updated |= checkModifiedBy(currentState, a, username, i, propertyName);
            }
        }

        return updated;
    }

    @Override
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
            Object[] previousState, String[] propertyNames, Type[] types) {
        boolean updated = false;
        if (entity instanceof Auditable) {
            Auditable a = (Auditable) entity;
            String username = getCurrentUser();
            Date stamp = new Date();
            for (int i = 0; i < propertyNames.length; i++) {
                String propertyName = propertyNames[i];
                updated |= checkModifiedOn(currentState, a, stamp, i, propertyName);
//                updated |= checkModifiedBy(currentState, a, username, i, propertyName);
            }
        }

        return updated;
    }

    private boolean checkModifiedOn(Object[] currentState, Auditable auditable, Date stamp, int idx,
            String propertyName) {
        if (propertyName.equals(updatedOnName)) {
            auditable.setModifiedOn(stamp);
            currentState[idx] = stamp;
            return true;
        } else {
            return false;
        }
    }

//    private boolean checkModifiedBy(Object[] currentState, Auditable auditable, String username,
//            int idx, String propertyName) {
//        if (propertyName.equals(updatedByName)) {
//            auditable.setModifiedBy(username);
//            currentState[idx] = username;
//            return true;
//        } else {
//            return false;
//        }
//    }

    private String getCurrentUser() {
        String currentUsername = "";

        try {
            currentUsername = SecurityContextHolder.getContext().getAuthentication().getName();
        } catch (java.lang.NullPointerException ne) {
            //Current user is anonymous
        }
        return currentUsername;
    }
}
